import { BaseService, CoolCommException } from '@cool-midway/core';
import { Provide } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository, Equal } from 'typeorm';
import {
  ProviderDepositEntity,
  DepositOperationType,
  DepositRecordStatus,
} from '../entity/deposit';
import { ProviderProfileEntity } from '../entity/profile';
import {
  PayDepositDTO,
  RefundDepositDTO,
  DeductDepositDTO,
  DepositPayCallbackDTO,
  DepositRecordPageDTO,
} from '../dto/deposit';
import * as moment from 'moment';

@Provide()
export class ProviderDepositService extends BaseService {
  @InjectEntityModel(ProviderDepositEntity)
  depositEntity: Repository<ProviderDepositEntity>;

  @InjectEntityModel(ProviderProfileEntity)
  profileEntity: Repository<ProviderProfileEntity>;

  /**
   * 生成订单号
   */
  private generateOrderNo(): string {
    const timestamp = moment().format('YYYYMMDDHHmmssSSS');
    const random = Math.floor(Math.random() * 10000)
      .toString()
      .padStart(4, '0');
    return `DEP${timestamp}${random}`;
  }

  /**
   * 获取服务人员当前质保金余额
   */
  async getBalance(providerId: number): Promise<number> {
    const profile = await this.profileEntity.findOne({
      where: { providerId: Equal(providerId) },
    });
    if (!profile) {
      throw new CoolCommException('服务人员信息不存在');
    }
    return Number(profile.depositAmount) || 0;
  }

  /**
   * 创建缴纳质保金订单
   */
  async createPayOrder(providerId: number, dto: PayDepositDTO) {
    const profile = await this.profileEntity.findOne({
      where: { providerId: Equal(providerId) },
    });
    if (!profile) {
      throw new CoolCommException('请先完善个人资料');
    }

    const currentBalance = Number(profile.depositAmount) || 0;
    const orderNo = this.generateOrderNo();

    const record = this.depositEntity.create({
      providerId,
      operationType: DepositOperationType.PAY,
      amount: dto.amount,
      beforeBalance: currentBalance,
      afterBalance: currentBalance + dto.amount,
      status: DepositRecordStatus.PENDING,
      orderNo,
      payMethod: dto.payMethod,
      remark: dto.remark,
    });

    await this.depositEntity.save(record);

    return {
      orderNo,
      amount: dto.amount,
      // 这里可以返回支付相关的信息，如支付链接、二维码等
    };
  }

  /**
   * 支付回调处理（支付成功后调用）
   */
  async payCallback(dto: DepositPayCallbackDTO) {
    const record = await this.depositEntity.findOne({
      where: { orderNo: Equal(dto.orderNo) },
    });

    if (!record) {
      throw new CoolCommException('订单不存在');
    }

    if (record.status !== DepositRecordStatus.PENDING) {
      throw new CoolCommException('订单状态异常');
    }

    // 更新记录状态
    record.status = DepositRecordStatus.COMPLETED;
    record.transactionId = dto.transactionId;
    record.paidAt = new Date();
    await this.depositEntity.save(record);

    // 更新服务人员质保金余额
    await this.profileEntity.update(
      { providerId: Equal(record.providerId) },
      { depositAmount: record.afterBalance }
    );

    return { success: true };
  }

  /**
   * 模拟支付成功（测试用）
   */
  async mockPaySuccess(providerId: number, orderNo: string) {
    const record = await this.depositEntity.findOne({
      where: { orderNo: Equal(orderNo), providerId: Equal(providerId) },
    });

    if (!record) {
      throw new CoolCommException('订单不存在');
    }

    if (record.status !== DepositRecordStatus.PENDING) {
      throw new CoolCommException('订单状态异常');
    }

    // 更新记录状态
    record.status = DepositRecordStatus.COMPLETED;
    record.transactionId = `MOCK_${Date.now()}`;
    record.paidAt = new Date();
    await this.depositEntity.save(record);

    // 更新服务人员质保金余额
    await this.profileEntity.update(
      { providerId: Equal(record.providerId) },
      { depositAmount: record.afterBalance }
    );

    return { success: true, balance: record.afterBalance };
  }

  /**
   * 申请退还质保金
   */
  async refund(providerId: number, dto: RefundDepositDTO) {
    const profile = await this.profileEntity.findOne({
      where: { providerId: Equal(providerId) },
    });

    if (!profile) {
      throw new CoolCommException('服务人员信息不存在');
    }

    const currentBalance = Number(profile.depositAmount) || 0;

    if (dto.amount > currentBalance) {
      throw new CoolCommException('退还金额不能超过当前余额');
    }

    const orderNo = this.generateOrderNo();
    const newBalance = currentBalance - dto.amount;

    const record = this.depositEntity.create({
      providerId,
      operationType: DepositOperationType.REFUND,
      amount: dto.amount,
      beforeBalance: currentBalance,
      afterBalance: newBalance,
      status: DepositRecordStatus.REFUNDED,
      orderNo,
      remark: dto.remark,
      paidAt: new Date(),
    });

    await this.depositEntity.save(record);

    // 更新服务人员质保金余额
    await this.profileEntity.update(
      { providerId: Equal(providerId) },
      { depositAmount: newBalance }
    );

    return { success: true, balance: newBalance };
  }

  /**
   * 扣除质保金（管理员操作）
   */
  async deduct(dto: DeductDepositDTO, operatorId: number) {
    const profile = await this.profileEntity.findOne({
      where: { providerId: Equal(dto.providerId) },
    });

    if (!profile) {
      throw new CoolCommException('服务人员信息不存在');
    }

    const currentBalance = Number(profile.depositAmount) || 0;

    if (dto.amount > currentBalance) {
      throw new CoolCommException('扣除金额不能超过当前余额');
    }

    const orderNo = this.generateOrderNo();
    const newBalance = currentBalance - dto.amount;

    const record = this.depositEntity.create({
      providerId: dto.providerId,
      operationType: DepositOperationType.DEDUCT,
      amount: dto.amount,
      beforeBalance: currentBalance,
      afterBalance: newBalance,
      status: DepositRecordStatus.COMPLETED,
      orderNo,
      remark: dto.remark,
      operatorId,
      paidAt: new Date(),
    });

    await this.depositEntity.save(record);

    // 更新服务人员质保金余额
    await this.profileEntity.update(
      { providerId: Equal(dto.providerId) },
      { depositAmount: newBalance }
    );

    return { success: true, balance: newBalance };
  }

  /**
   * 查询质保金记录（分页）
   */
  async recordPage(providerId: number, query: DepositRecordPageDTO) {
    const qb = this.depositEntity
      .createQueryBuilder('a')
      .where('a.providerId = :providerId', { providerId })
      .orderBy('a.id', 'DESC');

    if (query.operationType) {
      qb.andWhere('a.operationType = :operationType', {
        operationType: query.operationType,
      });
    }

    if (query.status !== undefined) {
      qb.andWhere('a.status = :status', { status: query.status });
    }

    const result = await this.entityRenderPage(qb, query);
    result.list = this.normalizeRawRows(result.list);
    return result;
  }

  /**
   * 格式化查询结果，去除表别名前缀
   */
  private normalizeRawRows(rows: any[] = []) {
    return rows.map(row => {
      const formatted = {};
      Object.keys(row).forEach(key => {
        // 去除 a_ 前缀
        const normalizedKey = key.replace(/^[a-z]+_/, '');
        formatted[normalizedKey] = row[key];
      });
      return formatted;
    });
  }

  /**
   * 获取质保金统计信息
   */
  async getStatistics(providerId: number) {
    const balance = await this.getBalance(providerId);

    // 累计缴纳
    const totalPaid = await this.depositEntity
      .createQueryBuilder('a')
      .select('SUM(a.amount)', 'total')
      .where('a.providerId = :providerId', { providerId })
      .andWhere('a.operationType = :type', { type: DepositOperationType.PAY })
      .andWhere('a.status = :status', { status: DepositRecordStatus.COMPLETED })
      .getRawOne();

    // 累计退还
    const totalRefund = await this.depositEntity
      .createQueryBuilder('a')
      .select('SUM(a.amount)', 'total')
      .where('a.providerId = :providerId', { providerId })
      .andWhere('a.operationType = :type', { type: DepositOperationType.REFUND })
      .andWhere('a.status = :status', { status: DepositRecordStatus.REFUNDED })
      .getRawOne();

    // 累计扣除
    const totalDeduct = await this.depositEntity
      .createQueryBuilder('a')
      .select('SUM(a.amount)', 'total')
      .where('a.providerId = :providerId', { providerId })
      .andWhere('a.operationType = :type', { type: DepositOperationType.DEDUCT })
      .andWhere('a.status = :status', { status: DepositRecordStatus.COMPLETED })
      .getRawOne();

    return {
      balance,
      totalPaid: Number(totalPaid?.total) || 0,
      totalRefund: Number(totalRefund?.total) || 0,
      totalDeduct: Number(totalDeduct?.total) || 0,
    };
  }
}

